package com.arpa.wms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.arpa.ntocc.common.common.cache.PartyCache;
import com.arpa.ntocc.common.common.cache.PartyGroupCache;
import com.arpa.ntocc.common.common.cache.ShipmentCache;
import com.arpa.ntocc.common.common.util.CommonUtil;
import com.arpa.ntocc.common.common.util.UserUtil;
import com.arpa.wms.cache.LocationCache;
import com.arpa.wms.cache.SupplierCache;
import com.arpa.wms.cache.UnitCache;
import com.arpa.wms.cache.WarehouseCache;
import com.arpa.wms.domain.dto.InboundDTO;
import com.arpa.wms.domain.dto.InboundImportDTO;
import com.arpa.wms.domain.entity.Inbound;
import com.arpa.wms.domain.entity.InboundItem;
import com.arpa.wms.domain.entity.Supplier;
import com.arpa.wms.domain.enums.InboundStatusEnum;
import com.arpa.wms.domain.enums.ReceiveTypeEnum;
import com.arpa.wms.domain.vo.InboundImportVO;
import com.arpa.wms.domain.vo.InboundItemVO;
import com.arpa.wms.domain.vo.InboundVO;
import com.arpa.wms.mapper.InboundMapper;
import com.arpa.wms.service.IInboundItemService;
import com.arpa.wms.service.IInboundService;
import com.arpa.wms.service.ISupplierService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.testng.collections.Lists;

import java.text.MessageFormat;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static com.arpa.wms.domain.consts.NumConst.NUM_ZERO;

/**
 * <p>
 * 入库单 服务实现类
 * </p>
 *
 * @author LEO
 * @since 2020-08-04
 */
@Service
public class InboundServiceImpl extends ServiceImpl<InboundMapper, Inbound> implements IInboundService {

    @Autowired
    private ShipmentCache shipmentCache;
    @Autowired
    private PartyCache partyCache;

    @Autowired
    private WarehouseCache warehouseCache;

    @Autowired
    private LocationCache locationCache;

    @Autowired
    private UnitCache unitCache;

    @Autowired
    private IInboundItemService iInboundItemService;
    @Autowired
    private PartyGroupCache partyGroupCache;
    @Autowired
    private ISupplierService iSupplierService;

    @Autowired
    private SupplierCache supplierCache;

    /**
     * 保存
     * @param entity
     * @return
     */
    @Override
    @Transactional(rollbackFor={Exception.class})
    public boolean save(Inbound entity) {
        if(StringUtils.isBlank(entity.getCode())){
            entity.setCode(IdUtil.simpleUUID());
        }
        if(StringUtils.isBlank(entity.getCreatedBy())){
            entity.setCreatedBy(UserUtil.getCode());
            entity.setCreatedName(partyCache.translate(UserUtil.getCode()));
        }

        return super.save(entity);
    }

    /**
     * 根据code更新实体
     * @param entity
     * @return
     */
    @Override
    @Transactional(rollbackFor={Exception.class})
    public int updateByCode(Inbound entity) {
        if(StringUtils.isBlank(entity.getModifiedBy())){
            entity.setModifiedBy(UserUtil.getCode());
            entity.setModifiedName(partyCache.translate(UserUtil.getCode()));
        }
        return baseMapper.update(entity,new QueryWrapper<Inbound>().lambda().eq(Inbound::getCode,entity.getCode()).eq(Inbound::getGroupCode,UserUtil.getBranchCode()));
    }

    /**
     * 查询列表
     * @param inboundDTO
     * @return
     */
    @Override
    public List<InboundVO> queryList(InboundDTO inboundDTO){
         inboundDTO.setGroupCode(UserUtil.getBranchCode());
        //排序字段名需要驼峰转数据库下划线类型字段名
        if(StringUtils.isNotEmpty(inboundDTO.getSortField())){
            inboundDTO.setSortField(CommonUtil.camel2Underline(inboundDTO.getSortField()));
        }
        List<InboundVO> inboundVOList = baseMapper.queryList(inboundDTO);

        // 添加创建人、修改人、所属机构名称翻译
        inboundVOList.forEach(e->{
            e.setTypeText(ReceiveTypeEnum.translate(e.getType()));
            //期初导入的时候会出现没有货主名称的情况，所以添加了如下代码
            if (StrUtil.isEmpty(e.getShipmentName())) {
                e.setShipmentName(shipmentCache.translate(e.getShipmentCode()));
            }
            e.setWarehouseName(warehouseCache.translate(e.getWarehouseCode()));
            e.setGroupName(partyGroupCache.translate(e.getGroupCode()));
        });

        return inboundVOList;
    }

    /**
     * 查询合计,包含总数
     * @param inboundDTO
     * @return
     */
    @Override
    public InboundVO queryListSum(InboundDTO inboundDTO){
        inboundDTO.setGroupCode(UserUtil.getBranchCode());
        if (IterUtil.isEmpty(inboundDTO.getShipmentCodes())) {
            return null;
        }

        StringBuilder sb = new StringBuilder();
        sb.append("SELECT ");
        inboundDTO.getShipmentCodes().stream().forEach(e -> {
            sb.append("(SELECT count(*) AS total FROM `wms_inbound`  WHERE 1=1 ");
            if (StrUtil.isNotEmpty(inboundDTO.getWarehouseCode())) {
                sb.append("and `warehouse_code` ='" + inboundDTO.getWarehouseCode());
            }
            if (StrUtil.isNotEmpty(inboundDTO.getGroupCode())) {
                sb.append("' and `group_code` ='" + inboundDTO.getGroupCode());
            }
            sb.append("' and `shipment_code` =  '" + e);
            if (ObjectUtil.isNotEmpty(inboundDTO.getDeleted())) {
                sb.append("' and `is_deleted` ='" + inboundDTO.getDeleted());
            } else {
                sb.append("' and `is_deleted` =  '" + NUM_ZERO);
            }

            if (StrUtil.isNotEmpty(inboundDTO.getCode())) {
                sb.append("' and `code` like'%" + inboundDTO.getCode() +"%");
            }
            if (StrUtil.isNotEmpty(inboundDTO.getSourceCode())) {
                sb.append("' and `source_code` like'%" + inboundDTO.getSourceCode() +"%");
            }
            if (StrUtil.isNotEmpty(inboundDTO.getShipmentName())) {
                sb.append("' and `shipment_name` like'%" + inboundDTO.getShipmentName() +"%");
            }

            if (StrUtil.isNotEmpty(inboundDTO.getStatus())) {
                sb.append("' and `status` ='" + inboundDTO.getStatus());
            }
            if (StrUtil.isNotEmpty(inboundDTO.getRemarks())) {
                sb.append("' and `remarks` ='" + inboundDTO.getRemarks());
            }
            if (StrUtil.isNotEmpty(inboundDTO.getId())) {
                sb.append("' and `id` ='" + inboundDTO.getId());
            }
            if (StrUtil.isNotEmpty(inboundDTO.getCreatedBy())) {
                sb.append("' and `created_by` ='" + inboundDTO.getCreatedBy());
            }

            if (ObjectUtil.isNotEmpty(inboundDTO.getGmtCreated())) {
                sb.append("' and `gmt_created` ='" + inboundDTO.getGmtCreated());
            }
            if (ObjectUtil.isNotEmpty(inboundDTO.getModifiedBy())) {
                sb.append("' and `modified_by` ='" + inboundDTO.getModifiedBy());
            }
            if (StrUtil.isNotEmpty(inboundDTO.getModifiedName())) {
                sb.append("' and `modified_name` ='" + inboundDTO.getModifiedName());
            }
            if (StrUtil.isNotEmpty(inboundDTO.getCreatedName())) {
                sb.append("' and `created_name` ='" + inboundDTO.getCreatedName());
            }
            if (ObjectUtil.isNotEmpty(inboundDTO.getGmtCreatedStart()) && ObjectUtil.isNotEmpty(inboundDTO.getGmtCreatedEnd())) {
                sb.append("' and `gmt_created` between '" + inboundDTO.getGmtCreatedStart() + "' and '" + inboundDTO.getGmtCreatedEnd());
            }
            if (ObjectUtil.isNotEmpty(inboundDTO.getGmtModifiedStart()) && ObjectUtil.isNotEmpty(inboundDTO.getGmtModifiedEnd())) {
                sb.append("' and `gmt_modified` between '" + inboundDTO.getGmtModifiedStart() + "' and '" + inboundDTO.getGmtModifiedEnd());
            }
            if (StrUtil.isNotEmpty(inboundDTO.getRemarks())) {
                sb.append("' and `remarks` ='" + inboundDTO.getRemarks());
            }
            if (StrUtil.isNotEmpty(inboundDTO.getId())) {
                sb.append("' and `id` ='" + inboundDTO.getId());
            }
            if (StrUtil.isNotEmpty(inboundDTO.getCreatedBy())) {
                sb.append("' and `created_by` ='" + inboundDTO.getCreatedBy());
            }
            sb.append("') +");
        });
        sb.replace(sb.length() - 1, sb.length(), "");
        sb.append("AS total ");

        return this.baseMapper.queryListSum(sb.toString());
    }

    /**
     * 查询合计,包含总数
     * @param inboundDTO
     * @return
     */
    @Override
    public InboundVO queryListTotal(InboundDTO inboundDTO){
        return this.baseMapper.queryListTotal(inboundDTO);
    }

    @Override
    public InboundVO getOneByCode(String code) {
        Inbound inbound = this.getOne(new QueryWrapper<Inbound>().lambda().eq(Inbound::getCode,code).eq(Inbound::getGroupCode,UserUtil.getBranchCode()));
        List<InboundItem> inboundItems = iInboundItemService.list(new QueryWrapper<InboundItem>().lambda()
                .eq(InboundItem::getInboundCode, inbound.getCode())
                .eq(InboundItem::getGroupCode,UserUtil.getBranchCode())
                .eq(InboundItem::getDeleted, 0));

        InboundVO inboundVO = new InboundVO();

        BeanUtil.copyProperties(inbound, inboundVO);
        inboundVO.setTypeText(ReceiveTypeEnum.translate(inboundVO.getType()));

        List<InboundItemVO> inboundItemVOS = new ArrayList<>();
        inboundItems.forEach(e->{
            InboundItemVO inboundItemVO = new InboundItemVO();
            BeanUtil.copyProperties(e, inboundItemVO);
            inboundItemVOS.add(inboundItemVO);
        });
        // 翻译
        inboundVO.setWarehouseName(warehouseCache.translate(inboundVO.getWarehouseCode()));
        inboundVO.setShipmentName(shipmentCache.translate(inboundVO.getShipmentCode()));
        inboundVO.setGroupName(partyGroupCache.translate(inboundVO.getGroupCode()));
        inboundItemVOS.stream().forEach(e->{
            e.setGoodsUnitName(unitCache.translate(e.getGoodsUnit()));
            e.setLocationName(locationCache.translate(e.getLocation()));
        });

        inboundVO.setInboundItemVOList(inboundItemVOS);
        return inboundVO;
    }

    /**
     * 一周内所有仓库的入库数量
     *
     * @return
     *
     */
    @Override
    public  List<Map<String,Object>> inboundCount(List<String> warehouseCodes,List<String> shipmentCodes,String fdt) {
        return baseMapper.inboundCount(warehouseCodes,shipmentCodes,fdt,UserUtil.getBranchCode());
    }

    /**
     * 批量插入入库单
     *
     * @param inbounds
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void batchInsert(List<Inbound> inbounds) {
        String createdBy = UserUtil.getCode();
        String createdName = partyCache.translate(createdBy);
        LocalDateTime nowTime = LocalDateTime.now();
        StringBuilder sql = new StringBuilder();
        // sql
        sql.append("insert into `wms_inbound` ( `id`, `code`, `warehouse_code`, `shipment_code`, " +
                "`shipment_name`, `group_code`, `source_code`, `type`, `gmt_order`, `plan_quantity`, `inbound_quantity`," +
                " `status`, `remarks`, `is_deleted`, `created_by`, `gmt_created`, `modified_by`, `gmt_modified`, " +
                "`created_name`, `modified_name`, `is_oms_order`) values ");

        String data = inbounds.stream().map(r -> {
            r.setDeleted(NUM_ZERO);
            return makeInboundSqlStr(r, createdBy, createdName, nowTime);
        }).collect(Collectors.joining(","));
        sql.append(data);

        this.baseMapper.execSql(sql.toString());
    }

    /**
     * 生成批量插入入库单sql数据
     * @param inbound
     * @param createdBy
     * @param createdName
     * @param nowTime
     * @return
     */
    public String makeInboundSqlStr(Inbound inbound, String createdBy, String createdName, LocalDateTime nowTime) {
        StringBuilder data = new StringBuilder();
        data.append("(");
        // id
        data.append("default, ");
        // code
        data.append("'").append(inbound.getCode()).append("',");
        // warehouse_code
        data.append("'").append(inbound.getWarehouseCode()).append("',");
        // shipment_code
        data.append("'").append(inbound.getShipmentCode()).append("',");
        // shipment_name
        data.append("'").append(inbound.getShipmentName()).append("',");
        // group_code
        data.append("'").append(inbound.getGroupCode()).append("',");
        // source_code
        data.append("'").append(inbound.getSourceCode()).append("',");
        // type
        data.append("'").append(inbound.getType()).append("',");
        // gmt_order
        if (ObjectUtil.isNull(inbound.getGmtOrder())) {
            data.append(StrUtil.NULL).append(",");
        } else {
            data.append("'").append(inbound.getGmtOrder()).append("',");
        }
        // plan_quantity
        if (ObjectUtil.isNull(inbound.getPlanQuantity())) {
            data.append(StrUtil.NULL).append(",");
        } else {
            data.append("'").append(inbound.getPlanQuantity()).append("',");
        }
        // inbound_quantity
        if (ObjectUtil.isNull(inbound.getInboundQuantity())) {
            data.append(StrUtil.NULL).append(",");
        } else {
            data.append("'").append(inbound.getInboundQuantity()).append("',");
        }
        // status
        data.append("'").append(inbound.getStatus()).append("',");
        // remarks
        data.append("'").append(StrUtil.EMPTY).append("',");
        // is_deleted
        data.append("'").append(NUM_ZERO).append("',");
        // created_by
        data.append("'").append(createdBy).append("',");
        // gmt_created
        data.append("'").append(nowTime).append("',");
        // modified_by
        data.append("'").append(createdBy).append("',");
        // gmt_modified
        data.append("'").append(nowTime).append("',");
        // created_name
        data.append("'").append(createdName).append("',");
        // modified_name
        data.append("'").append(createdName).append("',");
        // is_oms_order
        data.append("'").append(NUM_ZERO).append("'");

        data.append(")");

        return  data.toString();
    }

    /**
     * 入库订单数量统计 Visual
     * @return
     */
    @Override
    public String inboundQuantityTrend(String type, String time, String status){
        return baseMapper.inboundQuantityTrend(type, time, status);
    }


    /**
     * 入库单 导出数据
     * @param inboundDTO
     * @return
     */
    @Override
    public List<InboundImportVO> importInbound(InboundDTO inboundDTO) {
        //主单
        List<InboundImportVO> inboundImportVOList = baseMapper.importInbound(inboundDTO);

        if (IterUtil.isEmpty(inboundImportVOList)) {
            return Lists.newArrayList();
        }

        List<String> inboundCodes = inboundImportVOList.stream().map(e -> e.getInboundCode()).collect(Collectors.toList());
        //查询入库单明细信息
        Map<String,List<InboundItem>> listMap = iInboundItemService.list(new LambdaQueryWrapper<InboundItem>()
                .in(InboundItem::getInboundCode, inboundCodes)).stream()
                .collect(Collectors.groupingBy(InboundItem::getInboundCode));

        inboundImportVOList.forEach(e->{
            e.setTypeName(ReceiveTypeEnum.translate(e.getType()));
            e.setStatus(InboundStatusEnum.FINISH_IN.getValue());
            if(StringUtils.isNotBlank(e.getSupplierCode())){
                e.setSupplierName(supplierCache.translate(e.getSupplierCode()));
            }
            List<InboundItem> inboundItems = MapUtil.get(listMap, e.getInboundCode(), List.class);
            Set<String> skus = inboundItems.stream().map(InboundItem::getGoodsCode).collect(Collectors.toSet());
            e.setSku(String.valueOf(skus.size()));
        });

        return inboundImportVOList;
    }

    /**
     * 查询导入单合计,包含总数
     * @param inboundDTO
     * @return
     */
    @Override
    public InboundImportVO importInboundSum(InboundDTO inboundDTO){
        return this.baseMapper.importInboundSum(inboundDTO);
    }


    /**
     * 重构入参
     * @param inboundImportDTO
     * @return
     */
    @Override
    public InboundDTO constructQueryParams(InboundImportDTO inboundImportDTO,InboundDTO inboundDTO){
        if (StrUtil.isNotEmpty(inboundImportDTO.getInboundCode())) {
            inboundDTO.setCode(inboundImportDTO.getInboundCode());
        }
        List<String> inboundCodes = Lists.newArrayList();
//        根据商品数量查询逻辑
        if (null != inboundImportDTO.getSkuFloor() || null != inboundImportDTO.getSkuCeiling()) {
            List<InboundItemVO> inboundItemVOS = iInboundItemService.queryInboundGoodsSortQuantity();
            Map<String, List<InboundItemVO>> groupInboundCode = inboundItemVOS.stream().collect(Collectors.groupingBy(InboundItemVO::getInboundCode));
           //商品种数上限和下限都不为空
            if (null != inboundImportDTO.getSkuFloor() && null != inboundImportDTO.getSkuCeiling()) {
                for (Map.Entry<String,List<InboundItemVO>> entry : groupInboundCode.entrySet()) {
                    if (inboundImportDTO.getSkuFloor().intValue() <= entry.getValue().size() && entry.getValue().size() <=  inboundImportDTO.getSkuCeiling().intValue() ) {
                        inboundCodes.add(entry.getKey());
                    }
                }
            }
            //商品种数上限不为空，下限为空
            if (null != inboundImportDTO.getSkuFloor() && null == inboundImportDTO.getSkuCeiling()) {
                for (Map.Entry<String,List<InboundItemVO>> entry : groupInboundCode.entrySet()) {
                    if (inboundImportDTO.getSkuFloor().intValue() <= entry.getValue().size()) {
                        inboundCodes.add(entry.getKey());
                    }
                }
            }
            //商品种数上限为空，下限不为空
            if (null == inboundImportDTO.getSkuFloor() && null != inboundImportDTO.getSkuCeiling()) {
                for (Map.Entry<String,List<InboundItemVO>> entry : groupInboundCode.entrySet()) {
                    if (entry.getValue().size() <=  inboundImportDTO.getSkuCeiling().intValue() ) {
                        inboundCodes.add(entry.getKey());
                    }
                }
            }
            //根据商品数量查询时，如果没有查到期望的入库单code,设置入库单如下，目的是查询不到数据
            if (IterUtil.isEmpty(inboundCodes)) {
                inboundCodes.add("no result");
            }
        }

        if (StrUtil.isNotEmpty(inboundImportDTO.getSupplierCode())) {
            List<String> supplierCodes = iSupplierService.list(new LambdaQueryWrapper<Supplier>()
                    .select(Supplier::getCode)
                    .like(Supplier::getName, inboundImportDTO.getSupplierCode()))
                    .stream().map(Supplier::getCode)
                    .collect(Collectors.toList());
            inboundDTO.setSupplierCodes(supplierCodes);
        }
        //来源单号用的是收货单的来源单号，查询的时候也是
        if (StrUtil.isNotEmpty(inboundDTO.getSourceCode())) {
            inboundDTO.setReceiveSourceCode(inboundDTO.getSourceCode());
            inboundDTO.setSourceCode(StrUtil.EMPTY);
        }
        inboundDTO.setInboundCodes(inboundCodes);
        return inboundDTO;
    }

    public static String format(String value, Object... paras) {
        return MessageFormat.format(value, paras);
    }


}
